[][src]Crate tang_rs

A connection pool running one tokio runtime.

smoe code come from bb8 L3-37

Known Limitation:

No tests. can't be used in nested runtimes.

Example:

This example is not tested
use std::time::Duration;

use futures_util::TryStreamExt;
use tokio_postgres_tang::{Builder, PostgresPoolError, PostgresManager};

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let db_url = "postgres://postgres:123@localhost/test";

    // setup manager
    let mgr =
        PostgresManager::new_from_stringlike(
            db_url,
            tokio_postgres::NoTls,
        ).unwrap_or_else(|_| panic!("can't make postgres manager"));

    //make prepared statements to speed up frequent used queries. It just stores your statement info in a hash map and
    //you can skip this step if you don't need any prepared statement.
    let mgr = mgr
        // alias is used to call according statement later.
        // pass &[tokio_postgres::types::Type] if you want typed statement. pass &[] for no typed statement.
        .prepare_statement("get_topics", "SELECT * FROM topics WHERE id=ANY($1)", &[tokio_postgres::types::Type::OID_ARRAY])
        .prepare_statement("get_users", "SELECT * FROM posts WHERE id=ANY($1)", &[]);

    // make pool
    let pool = Builder::new()
        .always_check(false) // if set true every connection will be checked before checkout.
        .idle_timeout(None) // set idle_timeout and max_lifetime both to None to ignore idle connection drop.
        .max_lifetime(Some(Duration::from_secs(30 * 60)))
        .connection_timeout(Duration::from_secs(5)) // set the timeout when connection to database(used when establish new connection and doing always_check).
        .wait_timeout(Duration::from_secs(5)) // set the timeout when waiting for a connection.
        .min_idle(1)
        .max_size(12)
        .build(mgr)
        .await
        .unwrap_or_else(|_| panic!("can't make pool"));

    // wait a bit as the pool spawn connections asynchronously
    tokio::timer::delay(std::time::Instant::now() + std::time::Duration::from_secs(1)).await;

    // get a pool ref
    let pool_ref = pool.get().await.expect("can't get pool ref");

    // deref or derefmut to get connection.
    let (client, statements) = &*pool_ref;

    /*
        It's possible to insert new statement into statements from pool_ref.
        But be ware the statement will only work on this specific connection and not other connections in the pool.
        The additional statement will be dropped when the connection is dropped from pool.
        A newly spawned connection will not include this additional statement.

        * This newly inserted statement most likely can't take advantage of the pipeline query features
        as we didn't join futures when prepare this statement.

        * It's suggested that if you want pipelined statements you should join the futures of prepare before calling await on them.
        There is tang_rs::CacheStatement trait for PoolRef<PostgresManager<T>> to help you streamline this operation.
    */

    // use the alias input when building manager to get specific statement.
    let statement = statements.get("get_topics").unwrap();
    let rows = client.query(statement, &[]).await.expect("Query failed");

    // drop the pool ref to return connection to pool
    drop(pool_ref);

    // run the pool and use closure to query the pool.
    let _rows = pool
        .run(|mut conn| Box::pin(  // pin the async function to make sure the &mut Conn outlives our closure.
            async move {
                let (client, statements) = &conn;
                let statement = statements.get("get_topics").unwrap();
                let rows = client.query(statement, &[]).await?;

                // default error type.
                // you can infer your own error type as long as it impl From trait for tang_rs::PostgresPoolError
                Ok::<_, PostgresPoolError>(rows)
             }
        ))
        .await
        .map_err(|e| {
            match e {
                PostgresPoolError::Inner(e) => println!("{:?}", e),
                PostgresPoolError::TimeOut => ()
                };
            std::io::Error::new(std::io::ErrorKind::Other, "place holder error")
        })?;

   Ok(())
}

Structs

Builder
Conn
IdleConn
Pool
PoolRef
TokioTimeElapsed

Error returned by Timeout.

Traits

Manager

trait come from bb8.

Functions

tokio_spawn

Spawns a new asynchronous task, returning a JoinHandle for it.

Type Definitions

ManagerFuture